package com.woniuxueyuan.service.impl;

import com.alibaba.druid.sql.ast.statement.SQLIfStatement;
import com.alibaba.fastjson.JSON;
import com.woniuxueyuan.Producer.TopicProducer;
import com.woniuxueyuan.entity.KillBook;
import com.woniuxueyuan.entity.KillOrder;
import com.woniuxueyuan.service.SecKillService;
import com.woniuxueyuan.util.ResponseData;
import com.woniuxueyuan.util.SnowflakeIdGenerator;
import com.woniuxueyuan.util.UserContext;
import org.springframework.data.redis.core.HashOperations;
import org.springframework.data.redis.core.RedisTemplate;
import org.springframework.stereotype.Service;

import javax.annotation.Resource;
import java.text.ParseException;
import java.text.SimpleDateFormat;
import java.util.*;
import java.util.concurrent.TimeUnit;

@Service
public class SecKillServiceImpl implements SecKillService {
    @Resource
    private RedisTemplate redisTemplateInit;
    @Resource
    private TopicProducer topicProducer;

    /**
     * 接受秒杀书籍信息，放入redis，还要保存到秒杀表中
     * 使用rabbbitmq改造：
     * 书籍信息只会在开始时间前10分钟进入redis！
     * TTL时间=开始时间-当前时间-10分钟
     *
     * @param killBook
     */
//   SimpleDateFormat sdf= new SimpleDateFormat("yyyy-MM-dd HH:mm:ss");
    @Override
    public void addKillBook(KillBook killBook) {
//        Date startDate = sdf.parse(killBook.getStartTime());
//        //把时间转成时间戳
//        long subTime=startDate.getTime()-System.currentTimeMillis();
//        if(subTime>0){
//            long TTL=subTime-10*60*1000;
//        }
        //调用生产者发消息


        redisTemplateInit.opsForHash().put("SECKILLSERVICEIMPL:ADDKILLBOOK", killBook.getBookId() + "", killBook);
    }

    /**
     * 查询所有秒杀书籍
     *
     * @return
     */

    @Override
    public List<KillBook> queryAll() {
        Map<String, KillBook> killBookMap = redisTemplateInit.opsForHash().entries("SECKILLSERVICEIMPL:ADDKILLBOOK");
        Iterator<Map.Entry<String, KillBook>> iterator = killBookMap.entrySet().iterator();
        List<KillBook> killBooks = new ArrayList<>();
        //利用循环map，得到所有value值，放入集合中
        while (iterator.hasNext()) {
            Map.Entry<String, KillBook> next = iterator.next();
            killBooks.add(next.getValue());
        }
        return killBooks;
    }

    /**
     * 查询详情页
     * @param bookId
     * @return
     */

    @Override
    public KillBook queryDetail(Integer bookId) {
        KillBook cacheKillBook =(KillBook) redisTemplateInit.opsForHash().get("SECKILLSERVICEIMPL:ADDKILLBOOK",bookId+"");
        return cacheKillBook;

    }

    /**
     * 用户抢购
     * 1：判断书籍库存是否足够
     * 2：减库存
     * 3：生成秒杀订单（异步）
     *
     * 分布式锁
     * 应用场景：1：项目要集群部署 2：出现线程不安全代码
     * 实现方式：利用redis分布式锁。通过setnx指令的特点实现的
     *            特点：当用setnx指令放入一个数据时，先判断该key是否存在，
     *            如果存在不能放入，不存在可以放入
     *
     * 4：写入订单（改写成异步）
     * @param id
     * @return
     */

    @Override
    public Boolean startKill(Integer id) {
        //setIfAbsent()就是封装setnx指令
        //加锁时把线程标识放入value中
        //用uuid
      String uuid=null;
        try {
             uuid = UUID.randomUUID().toString();
            Boolean aBoolean = redisTemplateInit.opsForValue().setIfAbsent("lock", uuid,30, TimeUnit.SECONDS);
            KillBook cacheKillBook=null;
            if(aBoolean){
              cacheKillBook =(KillBook) redisTemplateInit.opsForHash().get("SECKILLSERVICEIMPL:ADDKILLBOOK",id+"");
            if(cacheKillBook==null || cacheKillBook.getKillNum()<=0){
                return false; //抢购结束
            }
            // 2：减库存
            cacheKillBook.setKillNum(cacheKillBook.getKillNum()-1);
            System.out.println("剩余库存："+cacheKillBook.getKillNum());
            //覆盖redis
            redisTemplateInit.opsForHash().put("SECKILLSERVICEIMPL:ADDKILLBOOK",id+"",cacheKillBook);



        }else{
                //没有获取锁的线程
                return false;

            }
            //3：生成秒杀订单（异步）
            KillOrder killOrder = new KillOrder();
            SnowflakeIdGenerator sfg = new SnowflakeIdGenerator();
            String orderNum = String.valueOf(sfg.nextId());
            killOrder.setKillOrderNum(orderNum);
            killOrder.setKillNum(1);
            killOrder.setStatus(1+"");
            killOrder.setPrice(cacheKillBook.getDiscountPrice());
            killOrder.setBookId(cacheKillBook.getBookId());
            Integer userId = UserContext.getUserId();
            killOrder.setUserId(userId);

            //都要给过期时间,大于网络波动时间
            redisTemplateInit.opsForValue().set(orderNum,orderNum,10,TimeUnit.MINUTES);
          //把对象转化成字符串用json
            String jsonString = JSON.toJSONString(killOrder);
            topicProducer.send("killOrder",jsonString);
            return true;
        } catch (Exception e){
            throw new RuntimeException();
        }


        finally {
            //只能释放当前线程自己加的锁
            if(uuid.equals(redisTemplateInit.opsForValue().get("lock"))){
                redisTemplateInit.delete("lock");
            }


        }
    }

}


